#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#include "Picture.h"
#include "ak_mem.h"
#include "ak_log.h"

static int fd_gui = 0;
static struct fb_fix_screeninfo fb_fix_screeninfo_param;                               //屏幕固定参数
static struct fb_var_screeninfo fb_var_screeninfo_param;                               //屏幕可配置参数

static double af_format_byte[  ] = { 2 , 3 , 2 , 3 , 1.5 , 1.5 , 4 , 4 , 4 , 4 , 0 };  //图形格式占用的字节数
static struct ak_tde_layer tde_layer_screen = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , GP_FORMAT_BGR888 } ; //屏幕图层
static struct ak_tde_layer tde_layer_temp = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , GP_FORMAT_BGR888 } ; //临时图层

extern void *osal_fb_mmap_viraddr(int fb_len, int fb_fd);
extern int osal_fb_munmap_viraddr(void *addr, int fb_len);

int ScreenInit()
{
    int i_screen_size;
    if( ak_tde_open( ) != 0 ) 
    {
        return -1;
    }

    /* 防止重复调用 */
    if ( fd_gui > 0 ) 
    {
        return 0;
    }
    else if ( ( fd_gui = open( DEV_GUI, O_RDWR ) ) > 0 ) 
    {
        if (ioctl(fd_gui, FBIOGET_FSCREENINFO, &fb_fix_screeninfo_param) < 0) 
        {
            close( fd_gui );
            return AK_FAILED;
        }
        if (ioctl(fd_gui, FBIOGET_VSCREENINFO, &fb_var_screeninfo_param) < 0) 
        {
            close( fd_gui );
            return AK_FAILED;
        }

        if ( DUAL_FB_FIX == AK_TRUE )  {                                        //如果使用双buffer的话则调用ioctl
            i_screen_size = fb_fix_screeninfo_param.smem_len / 2 ;
        }
        else {
            i_screen_size = fb_fix_screeninfo_param.smem_len ;
        }

        /* 检查size */
        if( fb_var_screeninfo_param.xres_virtual * fb_var_screeninfo_param.yres_virtual *
            af_format_byte[ tde_layer_screen.format_param ] > i_screen_size  ) 
        {
            ak_print_error_ex( MODULE_ID_APP, "SCREEN FORMAT ERROR. Assign pixels sizes(%0.0f) is more than screen pixels sizes(%d)\n",
                               fb_var_screeninfo_param.xres_virtual * fb_var_screeninfo_param.yres_virtual *
                               af_format_byte[ tde_layer_screen.format_param ], i_screen_size );
            close( fd_gui );
            return AK_FAILED;
        }
        void *pv_addr = osal_fb_mmap_viraddr(fb_fix_screeninfo_param.smem_len, fd_gui);//( void * )mmap( 0 , p_fb_fix_screeninfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd_gui, 0 );

        /* 设置屏幕的可配置参数 */
        fb_var_screeninfo_param.activate |= FB_ACTIVATE_FORCE;
        fb_var_screeninfo_param.activate |= FB_ACTIVATE_NOW;
        fb_var_screeninfo_param.xres = fb_var_screeninfo_param.xres_virtual;
        fb_var_screeninfo_param.yres = fb_var_screeninfo_param.yres_virtual;
        fb_var_screeninfo_param.bits_per_pixel = BITS_PER_PIXEL;
        fb_var_screeninfo_param.red.offset = OFFSET_RED;
        fb_var_screeninfo_param.red.length = LEN_COLOR ;
        fb_var_screeninfo_param.green.offset = OFFSET_GREEN;
        fb_var_screeninfo_param.green.length = LEN_COLOR ;
        fb_var_screeninfo_param.blue.offset = OFFSET_BLUE;
        fb_var_screeninfo_param.blue.length = LEN_COLOR ;
        if (ioctl(fd_gui, FBIOPUT_VSCREENINFO, &fb_var_screeninfo_param) < 0) 
        {
            close( fd_gui );
            return AK_FAILED;
        }
        /* 将图像的内存清零 */
        memset( pv_addr, 0 , fb_fix_screeninfo_param.smem_len );

        tde_layer_screen.width      = fb_var_screeninfo_param.xres;
        tde_layer_screen.height     = fb_var_screeninfo_param.yres;
        tde_layer_screen.pos_left   = 0;
        tde_layer_screen.pos_top    = 0;
        tde_layer_screen.pos_width  = fb_var_screeninfo_param.xres;
        tde_layer_screen.pos_height = fb_var_screeninfo_param.yres;
        tde_layer_screen.phyaddr    = fb_fix_screeninfo_param.smem_start;
        tde_layer_screen.format_param=GP_FORMAT_BGR888;

        void *p_vaddr_tmp = NULL;
        int ret;
        tde_layer_temp = tde_layer_screen;
        p_vaddr_tmp = ak_mem_dma_alloc( 1, i_screen_size ); 
        ret = ak_mem_dma_vaddr2paddr( p_vaddr_tmp , ( unsigned long * )&tde_layer_temp.phyaddr );    //获取源图片dma物理地址
        if(ret < 0)
        {
            printf("dma mem alloc fail!\n");
        }

        return AK_SUCCESS;
    }
    else 
    {
        return AK_FAILED;
    }
}

int LayerInit(struct ak_tde_layer *_layer, char *file_path)
{   
    FILE *pFILE = NULL;
    void *p_vaddr_src= NULL;
    long long i_filesize_src = _layer->width * _layer->height * af_format_byte[ _layer->format_param ];      //源图片的设定大小
    int ret;

    if( i_filesize_src > 0 ) 
    {
        p_vaddr_src = ak_mem_dma_alloc( 1, i_filesize_src );                         //分配pmem内存
        ret = ak_mem_dma_vaddr2paddr( p_vaddr_src , ( unsigned long * )&_layer->phyaddr );    //获取源图片dma物理地址
        if(ret < 0)
        {
            printf("dma mem alloc fail!\n");
        }
    }

    pFILE = fopen( file_path , "rb" );                                    //将图片内容读入pmem
    if(pFILE == NULL)
    {
        printf("open %s fail!\n", file_path);

    }
    fseek(pFILE, 0, SEEK_SET);
    ret = fread( ( char * )p_vaddr_src, 1, i_filesize_src, pFILE);
    if(ret > 0)
    {
        fclose( pFILE );
        printf("read %d!\n", ret);
    }
    else
    {
        printf("read error!\n");
        fclose(pFILE);
        return -1; 
    }
    return 0;
}

int PutBgLayer(struct ak_tde_layer *bg_layer)
{  
    return ak_tde_opt_blit(bg_layer, &tde_layer_temp);
}


int AddLayer(struct ak_tde_layer *_layer, int centerX, int centerY)
{
    struct ak_tde_layer layer_tgt;
    layer_tgt.height = tde_layer_temp.height;
    layer_tgt.width  = tde_layer_temp.width;
    layer_tgt.pos_left = centerX - _layer->pos_width/2;
    layer_tgt.pos_top  = centerY - _layer->pos_height/2;
    layer_tgt.pos_height= _layer->pos_height;
    layer_tgt.pos_width = _layer->pos_width;
    layer_tgt.phyaddr   = tde_layer_temp.phyaddr;
    layer_tgt.format_param = tde_layer_temp.format_param;


    if(centerX + _layer->pos_width/2  > layer_tgt.width \
    || centerY + _layer->pos_height/2 > layer_tgt.height\
    || layer_tgt.pos_left < 0\
    || layer_tgt.pos_top  < 0)
    {
        printf("Addlayer out of screen!\n");
        return -1;
    }
    else{}

    struct ak_tde_cmd tde_cmd;
    tde_cmd.opt = GP_OPT_TRANSPARENT|GP_OPT_BLIT;
    tde_cmd.tde_layer_dst = layer_tgt;
    tde_cmd.tde_layer_src = *_layer;
    tde_cmd.alpha = 15;
    if(ak_tde_opt(&tde_cmd))
    {
        printf("opt transparent fail!\n");
        return -1;
    }
    return 0;
}

int FillRect(int center_left, int center_top, int width, int height)
{
    struct ak_tde_layer layer_tgt;
    layer_tgt.height = tde_layer_temp.height;
    layer_tgt.width  = tde_layer_temp.width;
    layer_tgt.pos_left = center_left - width/2;
    layer_tgt.pos_top  = center_top - height/2;
    layer_tgt.pos_width = width;
    layer_tgt.pos_height= height;
    layer_tgt.phyaddr   = tde_layer_temp.phyaddr;
    layer_tgt.format_param = tde_layer_temp.format_param;

    if(center_left + width/2  > layer_tgt.width\
    || center_top + height/2 > layer_tgt.height\
    || layer_tgt.pos_left < 0\
    || layer_tgt.pos_top  < 0)
    {
        printf("Addlayer out of screen!\n");
        return -1;
    }
    else{}

    if(ak_tde_opt_fillrect(&layer_tgt, 0))
    {
        printf("opt fill rect fail!\n");
        return -1;
    }
    return 0;
}

int ScreenOutput()
{
    ak_tde_opt_blit(&tde_layer_temp, &tde_layer_screen);
    if ( DUAL_FB_FIX == AK_TRUE )  
    {                                                                           //如果使用双buffer的话则调用ioctl
        if(ioctl( fd_gui, FBIOPUT_VSCREENINFO, &fb_var_screeninfo_param ))         //相当于将主图片切换到次图片，次图片切换到主图片上
        {
            printf("ioctl fail!\n");
        }
        /* 换成另一个地方放图片 */
        DUAL_FB_VAR ^= 1;
        tde_layer_screen.phyaddr = fb_fix_screeninfo_param.smem_start + DUAL_FB_VAR * 1024 * 600 * 3 ;
    }
    else
    {
        tde_layer_screen.phyaddr = fb_fix_screeninfo_param.smem_start;
    }
    return 0;
}